package com.qd.system.service.msg.server;

import com.cdqidi.exception.QueueIsEmptyException;
import com.cdqidi.util.SpringContextHolder;
import com.qd.system.model.MsgReceive;
import com.qd.system.model.MsgReceiveContent;
import com.qd.system.model.MsgReport;
import com.qd.system.service.msg.base.MsgReceiveContentService;
import com.qd.system.service.msg.base.MsgReceiveService;
import com.qd.system.service.msg.base.MsgReportService;
import com.qd.system.service.msg.log.ProcessReceiveContentLog;
import com.qd.system.service.msg.log.ProcessReceiveLog;
import com.qd.system.service.msg.log.ProcessReportLog;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class MsgProcess {
    private MsgProcess() {

    }

    private static class SingletonHolder {
        private static final MsgProcess INSTANCE = new MsgProcess();
    }

    public static MsgProcess getInstance() {
        return MsgProcess.SingletonHolder.INSTANCE;
    }

    private boolean receiveLogStatus;
    private final LinkedList<MsgReceive> receiveLogs = new LinkedList<>();

    private boolean receiveContentLogStatus;
    private final LinkedList<MsgReceiveContent> receiveContentLogs = new LinkedList<>();

    private boolean reportLogStatus;
    private final LinkedList<MsgReport> reportLogs = new LinkedList<>();


    private final List<ProcessReceiveLog> processReceiveLogs = new ArrayList<>();
    private final List<ProcessReceiveContentLog> processReceiveContentLogs = new ArrayList<>();
    private final List<ProcessReportLog> processReportLogs = new ArrayList<>();


    public void addReceiveLog(MsgReceive receive) {
        synchronized (receiveLogs) {
            receiveLogs.add(receive);
            if (receiveLogStatus) {
                receiveLogStatus = false;
                receiveLogs.notifyAll();
            }
        }
    }

    public int getReceiveLogSize() {
        synchronized (receiveLogs) {
            return receiveLogs.size();
        }
    }

    public void getReceiveLog(List<MsgReceive> dataList) throws QueueIsEmptyException {
        synchronized (receiveLogs) {
            if (receiveLogs.isEmpty()) {
                receiveLogStatus = true;
                try {
                    receiveLogs.wait(5000);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                }
                if (!receiveLogs.isEmpty()) {
                    receiveLogStatus = false;
                    fillReceiveLog(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillReceiveLog(dataList);
            }
        }
    }

    private void fillReceiveLog(List<MsgReceive> dataList) {
        if (receiveLogs.size() > 99) {
            int c = 0;
            while (!receiveLogs.isEmpty()) {
                dataList.add(receiveLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(receiveLogs);
            receiveLogs.clear();
        }
    }

    public void addReceiveContentLog(MsgReceiveContent receiveContent) {
        synchronized (receiveContentLogs) {
            receiveContentLogs.add(receiveContent);
            if (receiveContentLogStatus) {
                receiveContentLogStatus = false;
                receiveContentLogs.notifyAll();
            }
        }
    }

    public int getReceiveContentLogSize() {
        synchronized (receiveContentLogs) {
            return receiveContentLogs.size();
        }
    }

    public void getReceiveContentLogSize(List<MsgReceiveContent> dataList) throws QueueIsEmptyException {
        synchronized (receiveContentLogs) {
            if (receiveContentLogs.isEmpty()) {
                receiveContentLogStatus = true;
                try {
                    receiveContentLogs.wait(5000);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                }
                if (!receiveContentLogs.isEmpty()) {
                    receiveContentLogStatus = false;
                    fillReceiveContentLog(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillReceiveContentLog(dataList);
            }
        }
    }

    private void fillReceiveContentLog(List<MsgReceiveContent> dataList) {
        if (receiveContentLogs.size() > 99) {
            int c = 0;
            while (!receiveContentLogs.isEmpty()) {
                dataList.add(receiveContentLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(receiveContentLogs);
            receiveContentLogs.clear();
        }
    }

    public void addReportLog(MsgReport report) {
        synchronized (reportLogs) {
            reportLogs.add(report);
            if (reportLogStatus) {
                reportLogStatus = false;
                reportLogs.notifyAll();
            }
        }
    }

    public int getReportLogSize() {
        synchronized (reportLogs) {
            return reportLogs.size();
        }
    }

    public void getReportLog(List<MsgReport> dataList) throws QueueIsEmptyException {
        synchronized (reportLogs) {
            if (reportLogs.isEmpty()) {
                reportLogStatus = true;
                try {
                    reportLogs.wait(5000);
                } catch (InterruptedException ignored) {
                    Thread.currentThread().interrupt();
                }
                if (!reportLogs.isEmpty()) {
                    reportLogStatus = false;
                    fillReportLog(dataList);
                    return;
                }
                throw new QueueIsEmptyException();
            } else {
                fillReportLog(dataList);
            }
        }
    }

    private void fillReportLog(List<MsgReport> dataList) {
        if (reportLogs.size() > 99) {
            int c = 0;
            while (!reportLogs.isEmpty()) {
                dataList.add(reportLogs.remove());
                c++;
                if (c > 99) {
                    break;
                }
            }
        } else {
            dataList.addAll(reportLogs);
            reportLogs.clear();
        }
    }

    public void startup() {
        MsgReceiveService msgReceiveService = SpringContextHolder.getBean(MsgReceiveService.class);
        MsgReceiveContentService msgReceiveContentService = SpringContextHolder.getBean(MsgReceiveContentService.class);
        MsgReportService msgReportService = SpringContextHolder.getBean(MsgReportService.class);

        int c = 1;
        for (int i = 0; i < c; i++) {
            ProcessReceiveLog processReceiveLog = new ProcessReceiveLog(i + 1, msgReceiveService);
            processReceiveLog.start();
            processReceiveLogs.add(processReceiveLog);
        }
        for (int i = 0; i < c; i++) {
            ProcessReceiveContentLog processReceiveContentLog = new ProcessReceiveContentLog(i + 1, msgReceiveContentService);
            processReceiveContentLog.start();
            processReceiveContentLogs.add(processReceiveContentLog);
        }
        for (int i = 0; i < c; i++) {
            ProcessReportLog processReportLog = new ProcessReportLog(i + 1, msgReportService);
            processReportLog.start();
            processReportLogs.add(processReportLog);
        }
    }

    public void shutdown() {
        for (ProcessReceiveLog processReceiveLog : processReceiveLogs) {
            processReceiveLog.doDone();
        }
        for (ProcessReceiveContentLog processReceiveContentLog : processReceiveContentLogs) {
            processReceiveContentLog.doDone();
        }
        for (ProcessReportLog processReportLog : processReportLogs) {
            processReportLog.doDone();
        }
        notifySte();
    }

    public void notifySte() {
        synchronized (receiveLogs) {
            receiveLogs.notifyAll();
        }
        synchronized (receiveContentLogs) {
            receiveContentLogs.notifyAll();
        }
        synchronized (reportLogs) {
            reportLogs.notifyAll();
        }
    }
}
